package com.flyduck.modules.app.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.flyduck.common.exception.BusinessException;
import com.flyduck.entity.*;
import com.flyduck.manager.*;
import com.flyduck.mapper.*;
import com.flyduck.modules.app.constant.AppConstant;
import com.flyduck.dto.AppCartItemDTO;
import com.flyduck.modules.app.mq.MqSender;
import com.flyduck.modules.app.service.AppOrderService;
import com.flyduck.modules.app.vo.delivery.AppDeliveryInfoRespVO;
import com.flyduck.modules.app.vo.order.*;
import com.flyduck.utils.BeanUtils;
import com.flyduck.utils.KdApiSearchUtils;
import com.flyduck.utils.PageUtils;
import com.flyduck.utils.TokenUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @program: vueshop
 * @description:
 * @author: flyduck
 * @create: 2024-05-20 20:45
 **/
@Service
public class AppOrderServiceImpl implements AppOrderService {

    @Resource
    private AppAddressManager appAddressManager;
    @Resource
    private TokenUtils tokenUtils;
    @Resource
    private AppAddressMapper appAddressMapper;
    @Resource
    private AppCartItemMapper appCartItemMapper;
    @Resource
    private AppProductMapper appProductMapper;
    @Resource
    private AppSkuStockMapper appSkuStockMapper;
    @Resource
    private AppOrderManager appOrderManager;
    @Resource
    private AppOrderMapper appOrderMapper;
    @Resource
    private AppOrderItemMapper appOrderItemMapper;
    @Resource
    private AppSkuStockManager appSkuStockManager;
    @Resource
    private MqSender mqSender;
    @Resource
    private AppRefundMapper appRefundMapper;
    @Resource
    private GenerateSnManager generateSnManager;
    @Resource
    private AppCartItemManager appCartItemManager;

    /**
     * 购物车购买、立即购买的订单预览
     * @param appOrderPreviewReqVO
     * @return
     */
    @Override
    public AppOrderPreviewRespVO previewOrder(AppOrderPreviewReqVO appOrderPreviewReqVO) {
        Long userId = tokenUtils.getCurrentUserId();
        //判断参数是否完整
        if(
                CollectionUtil.isEmpty(appOrderPreviewReqVO.getCartIds())
                        &&
                (appOrderPreviewReqVO.getProductId() == null || appOrderPreviewReqVO.getSkuId() == null || appOrderPreviewReqVO.getQuantity() == null)
        ){
            throw new BusinessException("参数不完整");
        }

        //获取收货地址
        //addressId为空，展示默认收货地址，如果没有默认收货地址，则不展示
        //addressId不为空，根据addressId获取收货地址
        AppAddress appAddress;
        if (appOrderPreviewReqVO.getAddressId() == null) {
            appAddress = appAddressManager.getDefaultAddress(userId);
        }else {
            appAddress = appAddressMapper.selectById(appOrderPreviewReqVO.getAddressId());
            if(!userId.equals(appAddress.getUserId())){
                throw new BusinessException("配送地址异常");
            }
        }

        //获取购物车的商品/立即购买的商品
        List<AppCartItemDTO> cartItemList = appCartItemManager.getCartItemList(appOrderPreviewReqVO.getCartIds(),
                userId,
                appOrderPreviewReqVO.getProductId(),
                appOrderPreviewReqVO.getSkuId(),
                appOrderPreviewReqVO.getQuantity());

        //计算总金额：价格 * 数量
        BigDecimal totalAmount = cartItemList.stream()
                .map(
                        cartItem -> cartItem.getPrice().multiply(
                                new BigDecimal(cartItem.getQuantity())
                        )
                ).reduce(BigDecimal.ZERO, BigDecimal::add);


        //优惠劵、运费等信息
        BigDecimal freight = new BigDecimal("0");
        totalAmount = totalAmount.add(freight);

        AppOrderPreviewRespVO appOrderPreviewRespVO = new AppOrderPreviewRespVO();
        AppOrderPreviewRespVO.AppAddressVO appAddressVO = BeanUtils.toBean(appAddress, AppOrderPreviewRespVO.AppAddressVO.class);
        appOrderPreviewRespVO.setAddress(appAddressVO);
        List<AppOrderPreviewRespVO.AppCartItemVO> appCartItemVOS = BeanUtils.toBeanList(cartItemList, AppOrderPreviewRespVO.AppCartItemVO.class);
        appOrderPreviewRespVO.setCartItems(appCartItemVOS);
        appOrderPreviewRespVO.setTotalAmount(totalAmount);
        appOrderPreviewRespVO.setFreight(freight);
        return appOrderPreviewRespVO;
    }



    @Override
    public String createOrder(AppOrderCreateReqVO appOrderCreateReqVO) {

        Long userId = tokenUtils.getCurrentUserId();


        // 判断收货地址
        AppAddress appAddress = appAddressMapper.selectById(appOrderCreateReqVO.getAddressId());
        if(appAddress == null || !userId.equals(appAddress.getUserId())){
            throw new BusinessException("收货地址异常");
        }


        //获取购物车的商品/立即购买的商品
        List<AppCartItemDTO> cartItemList = appCartItemManager.getCartItemList(appOrderCreateReqVO.getCartIds(),
                userId,
                appOrderCreateReqVO.getProductId(),
                appOrderCreateReqVO.getSkuId(),
                appOrderCreateReqVO.getQuantity());


        //计算总金额：价格 * 数量
        BigDecimal total = cartItemList.stream()
                .map(
                        cartItem -> cartItem.getPrice().multiply(
                                new BigDecimal(cartItem.getQuantity())
                        )
                ).reduce(BigDecimal.ZERO, BigDecimal::add);
        //优惠劵、运费等信息
        BigDecimal freight = new BigDecimal("0");
        total = total.add(freight);

        // 创建订单记录
        AppOrder appOrder = new AppOrder();
        appOrder.setUserId(userId);
        appOrder.setSn(generateSnManager.generateOrderSn());

        appOrder.setTotalAmount(total);
        appOrder.setFreight(freight);

        //收货人信息
        appOrder.setReceiverName(appAddress.getName());
        appOrder.setReceiverTel(appAddress.getTel());
        appOrder.setReceiverAddress(appAddress.getProvince() + appAddress.getCity() + appAddress.getCounty() + appAddress.getAddressDetail());
        appOrder.setReceiverPostalCode(appAddress.getPostalCode());
        appOrder.setReceiverAreaCode(appAddress.getAreaCode());

        appOrder.setOrderStatus(AppConstant.OrderStatus.PENDING_PAYMENT.getCode());
        appOrder.setIsDelete(false);
        appOrder.setCreated(LocalDateTime.now());
        appOrder.setNote(appOrderCreateReqVO.getNote());
        appOrderMapper.insert(appOrder);


        // 保存商品信息快照
        List<AppOrderItem> appOrderItemList = new ArrayList<>();
        for (AppCartItemDTO appCartItemDTO : cartItemList) {
            AppOrderItem appOrderItem = new AppOrderItem();
            appOrderItem.setProductId(appCartItemDTO.getProductId());
            appOrderItem.setProductName(appCartItemDTO.getProductName());
            appOrderItem.setProductImage(appCartItemDTO.getProductImage());
            appOrderItem.setProductSn(appCartItemDTO.getProductSn());
            appOrderItem.setCategoryId(appCartItemDTO.getCategoryId());
            appOrderItem.setPrice(appCartItemDTO.getPrice());
            appOrderItem.setQuantity(appCartItemDTO.getQuantity());

            appOrderItem.setSkuId(appCartItemDTO.getSkuId());
            appOrderItem.setSku(appCartItemDTO.getSku());

            appOrderItem.setOrderId(appOrder.getId());
            appOrderItem.setCreated(LocalDateTime.now());

            appOrderItemList.add(appOrderItem);
        }
        appOrderItemMapper.insertBatch(appOrderItemList);

        // 删除购物车的商品信息
        if(CollectionUtil.isNotEmpty(appOrderCreateReqVO.getCartIds())){
            appCartItemMapper.delete(
                    new LambdaQueryWrapper<AppCartItem>()
                    .eq(AppCartItem::getUserId,userId)
                    .in(AppCartItem::getId,appOrderCreateReqVO.getCartIds())

            );
        }

        // 判断库存并扣减库存
        appSkuStockManager.reduceStock(appOrderItemList);



        // 超时未支付则自动取消订单 - 死信队列
        mqSender.sendCancelOrderMessage(appOrder.getId());


        return appOrder.getSn();

    }

    @Override
    public AppOrderTotalCountRespVO getOrderTotalCount() {
        Long userId = tokenUtils.getCurrentUserId();

        List<AppOrder> appOrderList = appOrderMapper.selectList(
                new LambdaQueryWrapper<AppOrder>()
                        .eq(AppOrder::getUserId, userId)
        );

        //PENDING_PAYMENT(0, "待付款"),
        //PENDING_DELIVERY(1, "待发货"),
        //PENDING_RECEIPT(2, "待收货"),
        //COMPLETED(3, "已完成"),
        //CANCELLED(4, "已取消"),
        //REFUND_REQUESTED(5, "申请退款"),
        //REFUNDED(6, "已退款"),
        //REFUND_FAILED(7, "退款失败");
        int unPay = 0;//待付款
        int unDeli = 0;//待发货
        int unDecv = 0;//待收货
        int unRefund = 0;//退款中
        long unComment = 0;//待评论

        //订单状态：0->待付款；1->待发货；2->待收货；3-已完成；4->已取消；5-申请退款，6->已退款，7->退款失败
        //页面展示：待付款、待发货、待收货、待评论（几种商品有几个）、退款中
        for (AppOrder appOrder : appOrderList) {
            if (AppConstant.OrderStatus.PENDING_PAYMENT.getCode() == appOrder.getOrderStatus()) {
                unPay++;
            }else if(AppConstant.OrderStatus.PENDING_DELIVERY.getCode() == appOrder.getOrderStatus()){
                unDeli++;
            }else if(AppConstant.OrderStatus.PENDING_RECEIPT.getCode() == appOrder.getOrderStatus()){
                unDecv++;
            }else if(AppConstant.OrderStatus.REFUND_REQUESTED.getCode() == appOrder.getOrderStatus()){
                unRefund++;
            }
        }

        //已完成状态的所有订单id
        List<Long> completedOrderIds = appOrderList.stream()
                .filter(appOrder -> AppConstant.OrderStatus.COMPLETED.getCode() == appOrder.getOrderStatus())
                .map(AppOrder::getId)
                .collect(Collectors.toList());

        if (CollectionUtil.isNotEmpty(completedOrderIds)) {
            unComment = appOrderItemMapper.selectCount(
                    new LambdaQueryWrapper<AppOrderItem>()
                            .in(AppOrderItem::getOrderId, completedOrderIds)
                            .isNull(AppOrderItem::getCommentId)
            );
        }

        AppOrderTotalCountRespVO appOrderTotalCountRespVO = new AppOrderTotalCountRespVO();
        appOrderTotalCountRespVO.setUnPay(unPay);
        appOrderTotalCountRespVO.setUnDeli(unDeli);
        appOrderTotalCountRespVO.setUnDecv(unDecv);
        appOrderTotalCountRespVO.setUnRefund(unRefund);
        appOrderTotalCountRespVO.setUnComment(unComment);
        return appOrderTotalCountRespVO;
    }

    @Override
    public Page<AppOrderRespVO> getOrderPageByStatus(Page page, Integer status) {
        Long userId = tokenUtils.getCurrentUserId();

        Page<AppOrder> orderPage = appOrderMapper.selectPage(
                page,
                new LambdaQueryWrapper<AppOrder>()
                        .eq(AppOrder::getUserId, userId)
                        .eq(status != null, AppOrder::getOrderStatus, status)
                        .orderByDesc(AppOrder::getCreated)
        );
        Page<AppOrderRespVO> appOrderRespVOPage = PageUtils.convert(orderPage, AppOrderRespVO.class);
        for (AppOrderRespVO appOrderRespVO : appOrderRespVOPage.getRecords()) {
            List<AppOrderItem> appOrderItemList = appOrderItemMapper.getAppOrderItemListByOrderId(appOrderRespVO.getId());
            List<AppOrderRespVO.AppOrderItemVO> appOrderItemVOS = BeanUtils.toBeanList(appOrderItemList, AppOrderRespVO.AppOrderItemVO.class);
            appOrderRespVO.setOrderItems(appOrderItemVOS);
        }

        return appOrderRespVOPage;
    }

    @Override
    public AppOrderDetailsRespVO getOrderDetailsById(Long orderId) {
        AppOrder appOrder = appOrderManager.verifyAppOrderById(orderId);
        AppOrderDetailsRespVO appOrderDetailsRespVO = BeanUtils.toBean(appOrder, AppOrderDetailsRespVO.class);

        List<AppOrderItem> appOrderItemList = appOrderItemMapper.getAppOrderItemListByOrderId(orderId);
        List<AppOrderDetailsRespVO.AppOrderItemVO> appOrderItemVOS = BeanUtils.toBeanList(appOrderItemList, AppOrderDetailsRespVO.AppOrderItemVO.class);

        appOrderDetailsRespVO.setOrderItems(appOrderItemVOS);

        //申请退款、已退款的订单加上退款的信息
        if (Arrays.asList(AppConstant.OrderStatus.REFUND_REQUESTED.getCode(),AppConstant.OrderStatus.REFUNDED.getCode()).contains(appOrder.getOrderStatus())) {
            //退款单
            AppRefund appRefund = appRefundMapper.selectOne(
                    new LambdaQueryWrapper<AppRefund>()
                            .eq(AppRefund::getOrderId, appOrderDetailsRespVO.getId())
            );
            AppOrderDetailsRespVO.AppRefundVO appRefundVO = BeanUtils.toBean(appRefund, AppOrderDetailsRespVO.AppRefundVO.class);
            appOrderDetailsRespVO.setAppRefund(appRefundVO) ;
        }
        return appOrderDetailsRespVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelOrderById(Long orderId) {
        AppOrder appOrder = appOrderManager.verifyAppOrderById(orderId);

        if(AppConstant.OrderStatus.PENDING_PAYMENT.getCode() != appOrder.getOrderStatus()){
            throw new BusinessException("无法取消该订单");
        }

        //释放商品库存
        List<AppOrderItem> appOrderItemList = appOrderItemMapper.getAppOrderItemListByOrderId(orderId);
        appSkuStockManager.releaseStock(appOrderItemList);

        //更新订单状态为已取消
        appOrder.setOrderStatus(AppConstant.OrderStatus.CANCELLED.getCode());
        appOrder.setCompleteTime(LocalDateTime.now());
        appOrder.setUpdated(LocalDateTime.now());
        appOrderMapper.updateById(appOrder);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(Long orderId) {
        AppOrder appOrder = appOrderManager.verifyAppOrderById(orderId);
        //PENDING_PAYMENT(0, "待付款"),
        //PENDING_DELIVERY(1, "待发货"),
        //PENDING_RECEIPT(2, "待收货"),
        //COMPLETED(3, "已完成"),
        //CANCELLED(4, "已取消"),
        //REFUND_REQUESTED(5, "申请退款"),
        //REFUNDED(6, "已退款"),
        //REFUND_FAILED(7, "退款失败");
        if (!Arrays.asList(
                AppConstant.OrderStatus.PENDING_PAYMENT.getCode(),
                AppConstant.OrderStatus.COMPLETED.getCode(),
                AppConstant.OrderStatus.CANCELLED.getCode(),
                AppConstant.OrderStatus.REFUNDED.getCode()
        ).contains(appOrder.getOrderStatus())) {
            throw new BusinessException("无法删除该订单");
        }

        // 待付款订单 => 取消、释放库存
        if (AppConstant.OrderStatus.PENDING_PAYMENT.getCode() == appOrder.getOrderStatus()) {
            List<AppOrderItem> appOrderItemList = appOrderItemMapper.getAppOrderItemListByOrderId(orderId);
            appSkuStockManager.releaseStock(appOrderItemList);

            appOrder.setOrderStatus(AppConstant.OrderStatus.CANCELLED.getCode());
            appOrder.setCompleteTime(LocalDateTime.now());
            appOrder.setUpdated(LocalDateTime.now());
            appOrderMapper.updateById(appOrder);
        }

        appOrderMapper.deleteById(orderId);
    }

    @Override
    public AppDeliveryInfoRespVO getDeliveryInfoById(Long orderId) throws Exception {
        AppOrder appOrder = appOrderManager.verifyAppOrderById(orderId);

        String deliveryInfo = new KdApiSearchUtils().getDeliveryInfo(appOrder.getDeliveryCompany(), appOrder.getDeliverySn());

        JSONArray traces = JSONUtil.parseObj(deliveryInfo).getJSONArray("Traces");
        List<AppDeliveryInfoRespVO.AppDeliveryInfoVO> deliveryInfoVOList = traces.stream()
                .map(trace -> {
                    JSONObject jsonObject = JSONUtil.parseObj(trace);
                    AppDeliveryInfoRespVO.AppDeliveryInfoVO appDeliveryInfoVO = new AppDeliveryInfoRespVO.AppDeliveryInfoVO();
                    appDeliveryInfoVO.setAcceptTime(jsonObject.getStr("AcceptTime"));
                    appDeliveryInfoVO.setAcceptStation(jsonObject.getStr("AcceptStation"));
                    appDeliveryInfoVO.setRemark(jsonObject.getStr("Remark"));

                    return appDeliveryInfoVO;
                }).collect(Collectors.toList());


        AppDeliveryInfoRespVO appDeliveryInfoRespVO = new AppDeliveryInfoRespVO();
        appDeliveryInfoRespVO.setDeliveryInfo(deliveryInfoVOList);
        appDeliveryInfoRespVO.setDeliveryCompany(appOrder.getDeliveryCompany());
        appDeliveryInfoRespVO.setDeliverySn(appOrder.getDeliverySn());
        return appDeliveryInfoRespVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmOrderById(Long orderId) {
        AppOrder appOrder = appOrderManager.verifyAppOrderById(orderId);

        if (AppConstant.OrderStatus.PENDING_RECEIPT.getCode() != appOrder.getOrderStatus()) {
            throw new BusinessException("该订单无法确定收货");
        }

        // 更新商品销量
        List<AppProduct> updateAppProductList = new ArrayList<>();
        List<AppOrderItem> appOrderItemList = appOrderItemMapper.getAppOrderItemListByOrderId(orderId);
        for (AppOrderItem appOrderItem : appOrderItemList) {
            AppProduct appProduct = appProductMapper.selectById(appOrderItem.getProductId());
            appProduct.setSale(appProduct.getSale() + appOrderItem.getQuantity());
            updateAppProductList.add(appProduct);
        }
        appProductMapper.updateBatchById(updateAppProductList);

        // 更新订单状态为完成
        appOrder.setOrderStatus(AppConstant.OrderStatus.COMPLETED.getCode());
        appOrder.setReceiveTime(LocalDateTime.now());
        appOrder.setUpdated(LocalDateTime.now());
        appOrderMapper.updateById(appOrder);
    }
}
